from common import *


class AST:  # 定义抽象语法树类作为基类
	pass  # 暂时无内容


class BinaryOperator(AST):  # 定义二元运算符节点类
	def __init__(self, left, operator, right):  # 初始化
		self.left = left  # 运算符左侧子节点
		self.token = self.operator = operator  # 运算符记号和运算符节点
		self.right = right  # 运算符右侧子节点

	def __str__(self):
		# if isinstance(self.left, (type, types.ClassType)):
		return 'BinaryOperator(\n    {left},\n    {token},\n    {right}\n)'.format(left=self.left, token=self.token, right=self.right);
	#调试用于打印语法树
	def viewTree(self):
		return {
			'BinaryOperator':{
				'left':self.left.viewTree(),
				'token':self.token.viewTree(),
				'right':self.right.viewTree()
			}
		}


# 定义数字节点类
class Num(AST):
	def __init__(self, token):  # 初始化
		self.token = token  # 数字记号
		self.value = token.value  # 数字的值

	def __str__(self):
		return 'Num({token},{value})'.format(token=self.token, value=self.value)
	#调试用于打印语法树
	def viewTree(self):
		return {
			'Num':{'token':self.token.viewTree(),'value':self.value}
		}

# 定义一元运算符节点类,例如“-3”或“+3”以及“5–2”等等
class UnaryOperator(AST):
	# 初始化
	def __init__(self,operator,expr):
		self.token=self.operator=operator; # 运算符记号和运算符节点
		self.expr=expr # 一元运算符的子表达式

	def __str__(self):
		return 'UnaryOperator({token},{expr})'.format(token=self.token, expr=self.expr)
	#调试用于打印语法树
	def viewTree(self):
		return {
			'UnaryOperator':{
				'token':self.token.viewTree(),
				'expr':self.expr.viewTree(),
			}
		}

# 添加复合语句节点
class Compound(AST):
	def __init__(self):
		self.children = []  # 子节点列表

	def __str__(self):
		return 'Compound({children})'.format(children=self.children);
	#调试用于打印语法树
	def viewTree(self):
		lists=[]
		for index in range(len(self.children)):
			if type(self.children[index]).__name__=='Assign':
				lists.append(self.children[index].viewTree());
			if type(self.children[index]).__name__=='Compound':
				lists.append(self.children[index].viewTree());
			if type(self.children[index]).__name__=='NoOperator':
				lists.append(self.children[index].viewTree());
		return {
			'Compound':{'children':lists}
		}

# 添加赋值语句节点
class Assign(AST):
	def __init__(self, left, operator, right):
		self.left = left  # 变量名称
		self.token = self.operator = operator  # 记号和赋值符号
		self.right = right  # 右侧表达式
	def __str__(self):
		return 'Assign({left},{token},{right})'.format(left=self.left,token=self.token,right=self.right);
	#调试用于打印语法树
	def viewTree(self):
		token=self.token.viewTree();

		return {
			'left':self.left.viewTree(),
			'token':{'value_type':token['value_type'],'value':token['value']},
			'right':self.right.viewTree(),
		}

# 添加变量节点
class Variable(AST):
	def __init__(self, token):
		self.token = token  # 记号
		self.name = token.value  # 变量值
	def __str__(self):
		return 'Variable({token},{name})'.format(token=self.token,name=self.name);
	#调试用于打印语法树
	def viewTree(self):
		return {
			'Variable':{'token':self.token.viewTree(),'name':self.name}
		}

# 添加空语句节点
class NoOperator(AST):
	pass  # 无内容
	#调试用于打印语法树
	def viewTree(self):
		pass


class Program(AST):  # 定义程序节点
	def __init__(self, name, block):  # 程序由名称和语句块组成
		self.name = name
		self.block = block
	#调试用于打印语法树
	def viewTree(self):
		block=self.block.viewTree();
		return {
			'Program':{
				'name':self.name,
				'block':{
					'Block':{
						'declarations':block['declarations'],
						'compound_statement':block['compound_statement'],
					}
				}
			}
		};
class Block(AST):  # 定义语句块节点
	def __init__(self, declarations, compound_statement):  # 语句块由声明和符合语句组成
		self.declarations = declarations
		self.compound_statement = compound_statement
	#调试用于打印语法树
	def viewTree(self):
		declarations=[]
		for index in range(len(self.declarations)):
			declarations.append(self.declarations[index].viewTree());

		compound_statement=self.compound_statement.viewTree();
		return {
			'declarations':declarations,
			'compound_statement':compound_statement,
		};

class VarDecl(AST):  # 定义变量声明节点
	def __init__(self, var_node, type_node):  # 变量声明由变量和类型组成
		self.var_node = var_node
		self.type_node = type_node
	#调试用于打印语法树
	def viewTree(self):
		return {
			'VarDecl':{'var_node':self.var_node.viewTree(),'type_node':self.type_node.viewTree()}
		}

class Type(AST):  # 定义类型节点
	def __init__(self, token):
		self.token = token
		self.name = token.value
	#调试用于打印语法树
	def viewTree(self):
		return {
			'Type':{'token':self.token.viewTree(),'name':self.name}
		}

class Parser:  # 定义语法分析器的类
	def __init__(self, lexer):
		self.lexer = lexer  # 接收词法分析器对象
		self.current_token = lexer.get_next_token()

	def error(self):  # 增加语法分析器的错误方法
		raise Exception('警告：错误的输入内容！')

	# 添加获取变量节点的方法
	def variable(self):
		node = Variable(self.current_token)  # 获取变量节点
		self.eat(ID)  # 验证变量名称
		return node  # 返回变量节点
	# 添加获取空语句节点的方法
	def empty(self):
		return NoOperator()  # 返回空语句节点
	# 添加获取赋值语句节点的方法
	def assignment_statement(self):
		left = self.variable()  # 获取变量名称节点
		token = self.current_token  # 获取当前记号
		self.eat(ASSIGN)  # 验证赋值符
		right = self.expr()  # 获取表达式节点
		node = Assign(left, token, right)  # 组成赋值语句节点
		return node  # 返回赋值语句节点
	# 添加获取语句节点的方法
	def statement(self):
		if self.current_token.value_type == BEGIN:  # 如果遇到BEGIN，说明包含复合语句。
			node = self.compound_statement()  # 获取复合语句节点
		elif self.current_token.value_type == ID:  # 如果遇到一个名称，说明是赋值语句。
			node = self.assignment_statement()  # 获取赋值语句节点
		else:  # 否则就是空语句
			node = self.empty()  # 返回空语句节点
		return node  # 返回语句节点
	# 添加获取语句列表节点的方法
	def statement_list(self):
		node = self.statement()  # 获取第一条语句节点
		nodes = [node]  # 添加第一条语句节点到列表
		while self.current_token.value_type == SEMI:  # 如果遇到分号
			self.eat(SEMI)  # 验证分号
			nodes.append(self.statement())  # 添加下一条语句节点到列表
		if self.current_token.value_type == ID:  # 如果只遇到一个名称而非语句
			self.error()  # 抛出异常
		return nodes  # 返回语句节点列表
	# 添加获取复合语句节点的方法
	def compound_statement(self):
		self.eat(BEGIN)
		nodes = self.statement_list()  # 包含节点为语句列表
		self.eat(END)
		root = Compound()  # 创建复合语句节点对象
		root.children = nodes  # 将语句节点列表添作为复合语句节点的子节点列表
		return root  # 返回复合语句节点对象
	# 添加获取程序所有节点方法
	def program(self):
		self.eat(PROGRAM)  # 验证程序开始标记
		var_node = self.variable()  # 获取变量节点
		program_name = var_node.name  # 获取程序名称
		self.eat(SEMI)  # 验证分号
		block_node = self.block()  # 获取块节点
		print('program:')
		print(block_node)
		node = Program(program_name, block_node)  # 创建程序节点
		self.eat(DOT)  # 验证程序结束符号
		return node  # 返回程序节点


	def block(self):  # 构造块节点的方法
		declarations = self.declarations()
		compound_statement = self.compound_statement()
		node = Block(declarations, compound_statement) # 块节点由声明节点和符合语句节点组成
		return node

	def declarations(self):  # 构造声明节点的方法
		declarations = []  # 声明节点包含多个变量声明节点
		if self.current_token.value_type == VAR:  # 如果当前记号为变量
			self.eat(VAR)  # 验证记号
			while self.current_token.value_type == ID:  # 遍历变量名称
				declarations.extend(self.variable_declaration())  # 声明列表中添加变量声明
				self.eat(SEMI)  # 验证分号
		return declarations  # 返回声明节点列表

	def variable_declaration(self):  # 构造变量声明节点的方法
		var_nodes = [Variable(self.current_token)]  # 第一个变量声明节点添加到变量声明节点列表
		self.eat(ID)  # 验证变量名称记号
		while self.current_token.value_type == COMMA:  # 遍历逗号
			self.eat(COMMA)  # 验证逗号
			var_nodes.append(Variable(self.current_token))  # 添加变量节点到变量节点列表
			self.eat(ID)  # 验证变量名称记号
		self.eat(COLON)  # 验证冒号
		type_node = self.type_spec()  # 一组变量声明的类型节点
		# 生成变量声明列表
		var_declarations = [VarDecl(var_node, type_node) for var_node in var_nodes]
		return var_declarations  # 返回变量声明节点列表

	def type_spec(self):  # 构造变量类型节点的方法
		token = self.current_token  # 获取当前记号
		if token.value_type == INTEGER:  # 如果是整数类型
			self.eat(INTEGER)  # 验证整数记号
		else:  # 否则
			self.eat(REAL)  # 验证实数记号
		node = Type(token)  # 创建类型节点
		return node  # 返回类型节点


	#获取一下个token
	def eat(self, value_type):
		print(self.current_token.value_type)
		print(value_type)
		if self.current_token.value_type == value_type:
			self.current_token = self.lexer.get_next_token()
		else:
			self.error()

	'''
	  #  获取数字节点
	'''
	def factor(self):
		current_token = self.current_token

		if current_token.value_type == PLUS:
			self.eat(PLUS)
			node = UnaryOperator(current_token, self.factor())
			return node
		elif current_token.value_type == MINUS:
			self.eat(MINUS)
			node = UnaryOperator(current_token, self.factor())
			return node
		elif current_token.value_type == INTEGER_CONST:  # 整数
			self.eat(INTEGER_CONST)
			return Num(current_token)
		elif current_token.value_type == REAL_CONST:  # 实数
			self.eat(REAL_CONST)
			return Num(current_token)
		elif current_token.value_type == LPAREN:
			self.eat(LPAREN)
			node = self.expr()
			self.eat(RPAREN)
			return node
		else:
			node = self.variable()
			return node

	'''
	  #  先获取乘除节点
	'''
	def term(self):
		node = self.factor()
		while self.current_token.value_type in (MUL, INTEGER_DIV, FLOAT_DIV):  # 除法修改为整数除法和浮点数除法
			token = self.current_token
			if token.value_type == MUL:
				self.eat(MUL)
			elif token.value_type == INTEGER_DIV:  # 整数除法
				self.eat(INTEGER_DIV)
			elif token.value_type == FLOAT_DIV:  # 浮点数除法
				self.eat(FLOAT_DIV)
			node = BinaryOperator(node, token, self.factor())
		return node

	'''
	  #  后获取加减节点
	'''
	def expr(self):
		node = self.term()  # 左侧节点对象
		while self.current_token.value_type in (PLUS, MINUS):
			token = self.current_token
			if token.value_type == PLUS:
				self.eat(PLUS) #获取一下个token
			elif token.value_type == MINUS:
				self.eat(MINUS) #获取一下个token
			node = BinaryOperator(node, token, self.term())  # 返回二元运算表达式的节点
		return node  # 返回运算符节点对象

	# 定义语法分析器的方法
	def parser(self):
		node = self.program()  # 获取程序所有节点
		if self.current_token.value_type != EOF:  # 如果当前不是文件末端记号
			self.error()  # 抛出异常
		return node # 返回程序节点

